#region Copyright Statement
//  ------------------------------------------------------------------------------
//  
//    This file is part of The Streambolics Library.
//    Copyright © 2005-2009, Stephan Leclercq & Streambolics
//    All rights reserved.
//  
//    The Streambolics Library is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//  
//    The Streambolics Library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//  
//    You should have received a copy of the GNU General Public License
//    along with Streambolics; if not, write to the Free Software
//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//  
//  ------------------------------------------------------------------------------
#endregion

#region Change Log
//  
//  Commit: 11/11/2008 15:57:22 - SN118662190318\Stéphan Leclercq
//    Change: 17B18B1B-07ED-4CCF-B12A-5675042F584C: Miscellaneous Bugs & Enhancements
//    Reviewed: 11/11/2008 15:57:21 - SN118662190318\Stéphan Leclercq
//  
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Streambolics
{
    public enum DayPart
    {
        EarlyMorning,
        Morning,
        LunchTime,
        Afternoon,
        SupperTime,
        Evening
    }

    public static class DateTimeExtensions
    {
        /// <summary>
        ///     The date rendered as a string according to the format,
        ///     with "none" dates rendered as a default.
        /// </summary>
        /// <param name="aDateTime">
        ///     The date to format.
        /// </param>
        /// <param name="aFormat">
        ///     The format string to use.
        /// </param>
        /// <param name="aDefault">
        ///     The default representation for "none" dates.
        /// </param>
        /// <returns>
        ///     A string correponding to the date.
        /// </returns>
        /// <remarks><para>
        ///     DateTime values do not have a "never" value. The .NET solution would
        ///     be to use nullable date times. This however adds a considerable burden
        ///     to the system, as those dates need to be boxed.
        /// </para><para>
        ///     The "simple" solution is to treat DateTime.MinValue and DateTime.MaxValue
        ///     as "never" dates, and render them accordingly.
        /// </para></remarks>

        public static string ToStringDef (this DateTime aDateTime, string aFormat, string aDefault)
        {
            if (aDateTime == DateTime.MaxValue || aDateTime == DateTime.MinValue)
            {
                return aDefault;
            }
            else
            {
                return aDateTime.ToString (aFormat);
            }
        }

        public static string ToYearMonthDef (this DateTime aDateTime, string aDefault)
        {
            return ToStringDef (aDateTime, "MMMM yyyy", aDefault);
        }

        public static string ToYearMonthDef (this DateTime aDateTime)
        {
            return ToStringDef (aDateTime, "MMMM yyyy", String.Empty);
        }

        public static string ToMonthDayDef (this DateTime aDateTime, string aDefault)
        {
            return ToStringDef (aDateTime, "m", aDefault);
        }

        public static string ToMonthDayDef (this DateTime aDateTime)
        {
            return ToStringDef (aDateTime, "m", "");
        }

        /// <summary>
        ///     The date as a string, with nearby dates shown in reference
        ///     to today.
        /// </summary>
        /// <param name="aDateTime">
        ///     The date to convert.
        /// </param>
        /// <returns>
        ///     The date as either a full date (for distant dates,) day + month (for nearby dates)
        ///     or even "Today", "Yesterday", etc...
        /// </returns>

        public static string ToNearbyDateString (this DateTime aDateTime, string aDefault)
        {
            int d = (aDateTime.Date - DateTime.Today).Days;
            if (d == 0)
            {
                return "Today";
            }
            else if (d == - 1)
            {
                return "Yesterday";
            }
            else if (d == 1)
            {
                return "Tomorrow";
            }
            else if (d < -60 || d > 60)
            {
                return aDateTime.ToStringDef ("D", aDefault);
            }
            else
            {
                return aDateTime.ToMonthDayDef (aDefault);
            }
        }

        /// <summary>
        ///     The year and month parts of the date.
        /// </summary>
        /// <param name="aDateTime">
        ///     The date to truncate.
        /// </param>
        /// <returns>
        ///     A DateTime containing only the year and month of the source
        ///     date. The time component is set to 0, and the day in month is
        ///     1.
        /// </returns>

        public static DateTime YearAndMonth (this DateTime aDateTime)
        {
            return new DateTime (aDateTime.Year, aDateTime.Month, 1);
        }

        public static string ToNearbyDateAndDayPartString (this DateTime aDateTime)
        {
            return ToNearbyDateString (aDateTime, "") + " " + ToDayPartString (aDateTime);
        }

        public static DayPart ToDayPart (this DateTime aDateTime)
        {
            int h = aDateTime.Hour;
            if (h < 7)
            {
                return DayPart.EarlyMorning;
            }
            else if (h < 12)
            {
                return DayPart.Morning;
            }
            else if (h < 14)
            {
                return DayPart.LunchTime;
            }
            else if (h < 18)
            {
                return DayPart.Afternoon;
            }
            else if (h < 20)
            {
                return DayPart.SupperTime;
            }
            else
            {
                return DayPart.Evening;
            }
        }

        public static DateTime NormalizeDayPart (this DateTime aDateTime)
        {
            int h;
            switch (aDateTime.ToDayPart ())
            {
                case DayPart.EarlyMorning:
                    h = 0;
                    break;
                case DayPart.Morning:
                    h = 8;
                    break;
                case DayPart.LunchTime:
                    h = 12;
                    break;
                case DayPart.Afternoon:
                    h = 14;
                    break;
                case DayPart.SupperTime:
                    h = 18;
                    break;
                case DayPart.Evening:
                    h = 20;
                    break;
                default:
                    throw new ArgumentException ();
            }
            return aDateTime.Date.AddHours (h);
        }

        public static string ToDayPartString (this DateTime aDateTime)
        {
            switch (ToDayPart(aDateTime))
            {
                case DayPart.EarlyMorning:
                    return "Early morning";
                case DayPart.Morning:
                    return "Morning";
                case DayPart.LunchTime:
                    return "Lunch Time";
                case DayPart.Afternoon:
                    return "Afternoon";
                case DayPart.SupperTime:
                    return "Supper Time";
                case DayPart.Evening:
                    return "Evening";
                default:
                    throw new ArgumentException ();
            }
        }

        public static string ToSortableString (this DateTime aDateTime)
        {
            return aDateTime.ToString ("yyyyMMdd.HHmmss");
        }

        public static bool Reached (this DateTime aDateTime)
        {
            return DateTime.Now >= aDateTime;
        }

        public static string ToUniversalString (this DateTime aDateTime)
        {
            return aDateTime.ToString ("yyyy-MM-dd HH:mm:ss");
        }
    }
}
